import * as BABYLON from '@babylonjs/core';
import * as GUI from '@babylonjs/gui';
import { TWcsSceneDevice3d } from '../models/TWcsSceneDevice3d';
import { BabylonScene } from './BabylonScene';
import { TWcsSceneDeviceInfo } from '../models';
import { KrData } from './KrData';
import { ClassHelper } from '../ClassHelper';
import { Device2D } from './2d/controls/Device2D';
import { TWcsSceneDevice2d } from '../models/TWcsSceneDevice2d';

export abstract class AbstractDevice<TDevice extends GUI.Container | BABYLON.Mesh, TData extends TWcsSceneDevice3d | TWcsSceneDevice2d> {
  public id: string;
  public data: TData;
  public info: KrData = new KrData();
  public updateInfo: KrData = new KrData();
  public animations: Map<string, BABYLON.AnimationGroup> = new Map<string, BABYLON.AnimationGroup>();
  public deviceObject?: TDevice;

  protected scene: BabylonScene;
  protected tWcsLayoutInfoColors: TWcsSceneDeviceInfo[] = [];

  /**
   * 初始化 AbstractDevice 设备。
   * @param {BabylonScene<TDevice>} scene 当前设备所属场景。
   * @param {TWcsSceneDevice3d} data  布局对象数据支持。
   */
  protected constructor(scene: BabylonScene, data: TData) {
    this.scene = scene;
    this.data = data;
    this.id = this.data instanceof TWcsSceneDevice3d ? this.data.layoutObjectId : this.data.controlId;
    if (this.data.brandModelId) {
      this.tWcsLayoutInfoColors = this.scene.canvas.getTWcsSceneObjectInfoColors(this.data.brandModelId);
    }
  }

  public init(): void {
    // 设置当前设备扩展属性。
    if (this.data.extendInfos) {
      ClassHelper.setPropertiesFromJson(this, this.data.extendInfos);
    }

    // 安装设备对象。
    this.deviceObject = this.setupDeviceObject();

    // 安装设备动画，以便在信息变化时可以按信息条件执行动画。
    this.animations = this.setupAnimations();
  }

  public update(info: KrData): void {
    this.updateInfo = info;
    this.render();
  }

  public play(...names: string[]): void {
    for(var name of names) {
      var group = this.animations.get(name);
      group?.play();
    }
  }
  public abstract render(): void;
  public abstract contains(sceneX: number, sceneY: number): boolean;

  protected abstract setupDeviceObject(): TDevice | undefined;
  protected abstract setupAnimations(): Map<string, BABYLON.AnimationGroup>;
}
